﻿#region License
//-----------------------------------------------------------------------------
// Copyright (c) 2008, Aaron MacDougall, Daniel Jeffery
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
//   this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// * Neither the name of Aaron MacDougall or Daniel Jeffery nor the names of its contributors may
//   be used to endorse or promote products derived from this software without
//   specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;
#if WINDOWS
using System.Windows.Forms;
#endif
#endregion

namespace Agro2D
{
    /// <summary>
    /// Deletegate for Log Listeners.
    /// </summary>
    /// <param name="message"></param>
    public delegate void LogListenerDelegate(string message);

    /// <summary>
    /// Logs strings to files. Possbile performance hog, disable for release builds.
    /// </summary>  
    public class Log
    {

        #region Agro2DTraceListener

        /// <summary>
        /// Outputs callstack and error to Log on Debug fail.
        /// </summary>
        private class Agro2DTraceListener : TraceListener
        {
            public override void Write(string message)
            {
                Log.Instance.LogMessage(message);
            }

            public override void WriteLine(string message)
            {
                Log.Instance.LogMessage(message);
            }

            // TO DO: #ifdef for 360
            public override void Fail(string message, string detailMessage)
            {
#if WINDOWS
                StackTrace st =
                        new System.Diagnostics.StackTrace(true);

                string stacktrace = string.Empty;
                for(int i = 5; i < st.FrameCount; i++) // Start at 5 to ignore debugging calls.
                {
                    StackFrame sf = st.GetFrame(i);
                    stacktrace += "File: " + sf.GetFileName() +
                            "  Line: " + sf.GetFileLineNumber() +
                            "  Method: " + sf.GetMethod() + "\n";
                }

                string outMessage = "An Assert has failed with the following message:" +
                    "\n" + message + "\n\n" + stacktrace;

                Log.Instance.LogMessage("\n************************************************\n"
                    + outMessage + "************************************************");

                DialogResult res = MessageBox.Show(outMessage + "\n" + "Do you wish to continue execution?",
                    "Assert Failure",
                    MessageBoxButtons.YesNo, MessageBoxIcon.Error);
                if(res == DialogResult.No)
                {
                    Environment.Exit(1);
                }
#endif
            }

            public override void Fail(string message)
            {
                this.Fail(message, "");
            }
        }
        #endregion


        #region Cstors/Dstors
        public Log(string file)
        {
#if WINDOWS
            // create a writer and open the file
            mFile = file;
            tw = new StreamWriter(mFile);
#endif
            Debug.Listeners.Clear();

            Agro2DTraceListener trace = new Agro2DTraceListener();
            Debug.Listeners.Add(trace);

            // Remove default GUI so we can output to Log.
            listener = new DefaultTraceListener();
#if WINDOWS
            listener.AssertUiEnabled = false;
#endif
            Trace.Listeners.Add(listener);


        }
        #endregion

        #region Singleton Methods
        public static Log Instance
        {
            get
            {
                return instance;
            }
        }
        #endregion

        #region Public Interface
        public void LogMessage(string message)
        {

            if(!mEnabled)
                return;
            // write a line of text to the file
            if(LogListeners != null) // fire event to listeners
                LogListeners(message.TrimEnd('\n'));
#if WINDOWS
            tw.WriteLine(message);
            tw.Flush();
#endif
            listener.WriteLine(message);
        }
        #endregion

        #region Properties
        public bool Enabled
        {
            set { mEnabled = value; }
            get { return mEnabled; }
        }
        #endregion

        #region Attributes
        private static readonly Log instance = new Log("Game.log");
        public event LogListenerDelegate LogListeners;
        private DefaultTraceListener listener;
        private TextWriter tw;
        private string mFile;
        private bool mEnabled = true;
        #endregion
    }

    
}
